package com.example.demo.config.mybatis.plugin;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.xmltags.DynamicContext;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class BaseDataPrivilegeInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement ms=(MappedStatement)invocation.getArgs()[0];//获取MappedStatement
        SqlSource sqlSource=ms.getSqlSource();//获取sqlsource
        Object parameter =invocation.getArgs()[1];
        if(sqlSource instanceof DynamicSqlSource){//判断是否为动态sql
            Field field=sqlSource.getClass().getDeclaredField("rootSqlNode");//通过反射获取sqlNode
            field.setAccessible(true);
            SqlNode sqlNode=(SqlNode) field.get(sqlSource);//通过反射获取sqlNode
            //对sqlNode进行动态代理
            SqlNode proxyNode=(SqlNode) Proxy.newProxyInstance(sqlNode.getClass().getClassLoader(),new Class[]{SqlNode.class},new SqlNodeInvocationHandler(sqlNode,ms,parameter));
            field.set(sqlSource, proxyNode);
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

    private class SqlNodeInvocationHandler implements InvocationHandler{

        private SqlNode target;
        private MappedStatement ms;
        private Object parameter;

        private SqlNodeInvocationHandler(SqlNode target,MappedStatement ms,Object parameter){
            this.target=target;
            this.ms=ms;
            this.parameter=parameter;
        }


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            DynamicContext context = (DynamicContext) args[0];
            context.bind("DP","1!=1");
            return method.invoke(target,args);
        }
    }
}
